﻿using System;
using System.Collections.Generic;
using Internal.KuiHuaBaoDian.Services.Avatar;
using KuiHuaBaoDian.Services.Avatar;
using UnityEngine;
using UnityEngine.Assertions;

namespace KuiHuaBaoDian.Services.Avatar {

    /// <summary>
    /// 换装服务
    /// </summary>
    public static class AvatarService {

        /// <summary>
        /// 单例
        /// </summary>
        public static IAvatarService Instance => m_Instance ??= KHBD.TypeMap.Instantiate<IAvatarService>();
        private static IAvatarService m_Instance;
    }

    /// <summary>
    /// 换装服务
    /// </summary>
    public interface IAvatarService {

        /// <summary>
        /// 创建一个新的换装实例
        /// </summary>
        /// <param name="skeletonGameObject">骨骼</param>
        /// <returns>换装实例句柄</returns>
        AvatarHandle Create(GameObject skeletonGameObject);

        /// <summary>
        /// 销毁
        /// </summary>
        /// <param name="handle">换装实例句柄</param>
        void Dispose(AvatarHandle handle);

        /// <summary>
        /// 添加部件
        /// </summary>
        /// <param name="handle">换装实例句柄</param>
        /// <param name="partGameObject">部件<see cref="GameObject"/></param>
        /// <param name="additionalPartSetting">附加部件配置</param>
        /// <returns>换装部件实例句柄</returns>
        AvatarPartHandle AddPart(AvatarHandle handle, GameObject partGameObject, AvatarAdditionalPartSetting additionalPartSetting);

        /// <summary>
        /// 移除部件
        /// </summary>
        /// <param name="handle">换装实例句柄</param>
        /// <param name="partHandle">换装部件实例句柄</param>
        /// <param name="additionalPartSetting">附加部件配置</param>
        void RemovePart(AvatarHandle handle, AvatarPartHandle partHandle, AvatarAdditionalPartSetting additionalPartSetting);
    }

    [Implement(typeof(IAvatarService))]
    internal sealed class KHBD_AvatarService : IAvatarService, IAvatarServiceInternal, IService {

        private record Record(IAvatar Avatar);

        private readonly IDictionary<AvatarHandle, Record> m_Dictionary = new Dictionary<AvatarHandle, Record>();

        void IService.OnApplicationQuit() {
            m_Dictionary.Clear();
        }

        public AvatarHandle Create(GameObject skeletonGameObject) {
            Assert.IsNotNull(skeletonGameObject);

            var avatar = KHBD.TypeMap.Instantiate<IAvatar>();
            avatar.Initialize(skeletonGameObject);
            m_Dictionary.Add(avatar.Handle, new Record(avatar));
            return avatar.Handle;
        }

        public void Dispose(AvatarHandle handle) {
            if (m_Dictionary.TryGetValue(handle, out var record)) {
                m_Dictionary.Remove(handle);
                var avatar = record.Avatar;
                (avatar as IDisposable).Dispose();
            }
        }

        public AvatarPartHandle AddPart(AvatarHandle handle, GameObject partGameObject, AvatarAdditionalPartSetting additionalPartSetting) {
            Assert.IsFalse(handle.Equals(AvatarHandle.None));
            Assert.IsNotNull(partGameObject);

            var record = m_Dictionary[handle];
            var avatar = record.Avatar;
            return avatar.AddPart(partGameObject, additionalPartSetting);
        }

        public void RemovePart(AvatarHandle handle, AvatarPartHandle partHandle, AvatarAdditionalPartSetting additionalPartSetting) {
            Assert.IsFalse(handle.Equals(AvatarHandle.None));
            Assert.IsNotNull(partHandle);

            if (m_Dictionary.TryGetValue(handle, out var record)) {
                var avatar = record.Avatar;
                avatar.RemovePart(partHandle, additionalPartSetting);
            }
        }

        Transform IAvatarServiceInternal.GetBoneTransform(AvatarHandle handle, string boneName) {
            Assert.IsFalse(handle.Equals(AvatarHandle.None));
            Assert.IsFalse(string.IsNullOrEmpty(boneName));

            if (m_Dictionary.TryGetValue(handle, out var record)) {
                var avatar = record.Avatar;
                (avatar as IAvatarInternal).TryGetBone(boneName, out var boneTransform);
                return boneTransform;
            }
            return null;
        }

        Transform IAvatarServiceInternal.GetTransform(AvatarHandle handle) {
            Assert.IsFalse(handle.Equals(AvatarHandle.None));

            var record = m_Dictionary[handle];
            var avatar = record.Avatar;
            return (avatar as IAvatarInternal).SkeletonTransform;
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.Avatar {

    public interface IAvatarServiceInternal {

        Transform GetTransform(AvatarHandle handle);

        Transform GetBoneTransform(AvatarHandle handle, string boneName);
    }
}